package com.diy.sigmund.diycommon.spring.interceptor;

import com.diy.sigmund.diycommon.entity.constant.LogConstant;
import com.diy.sigmund.diycommon.util.json.JacksonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.context.request.async.DeferredResultProcessingInterceptor;

/**
 * 延迟结果处理接收器
 * <br>拦截并发请求处理，其中通过等待从应用程序选择的线程设置DeferredResult获得并发结果（例如响应某些外部事件）。
 * <br>DeferredResultProcessingInterceptor在异步处理开始之前、在设置DeferredResult之后以及在超时/错误时或在由于任何原因（包括超时或网络错误）完成之后被调用。
 * <br>作为一般规则，拦截器方法引发的异常将通过分派回容器并使用 Exception 实例作为并发结果来恢复异步处理。此类异常随后将通过HandlerExceptionResolver机制进行处理。
 * <br>handleTimeout方法可以设置DeferredResult以恢复处理。
 * <br>自从：
 * <br>3.2
 * <br>作者：
 * <br>罗森·斯托扬切夫，罗伯·温奇
 *
 * @author ylm-sigmund
 * @since 2022/8/7 14:56
 */
public class CustomDeferredResultProcessingInterceptor implements DeferredResultProcessingInterceptor {

    private static final Logger log = LoggerFactory.getLogger(CustomDeferredResultProcessingInterceptor.class);

    /**
     * <br>在并发处理开始之前立即调用，在启动它的同一线程中。此方法可用于在使用给定的DeferredResult开始并发处理之前捕获状态。
     * <br>参数：
     * <br>request – 当前请求
     * <br>deferredResult – 当前请求的 DeferredResult
     * <br>抛出：
     * <br>Exception ——如果出现错误
     */
    @Override
    public <T> void beforeConcurrentHandling(NativeWebRequest request, DeferredResult<T> deferredResult) throws Exception {
        log.info(LogConstant.SPRING_LOG, "DeferredResultProcessingInterceptor beforeConcurrentHandling 开始");
        DeferredResultProcessingInterceptor.super.beforeConcurrentHandling(request, deferredResult);
    }

    /**
     * <br>在并发处理开始后立即在启动它的同一线程中调用。此方法可用于检测具有给定DeferredResult的并发处理的开始。
     * <br>DeferredResult可能已经设置，例如在其创建时或由另一个线程设置。
     * <br>参数：
     * <br>request – 当前请求
     * <br>deferredResult – 当前请求的 DeferredResult
     * <br>抛出：
     * <br>Exception ——如果出现错误
     */
    @Override
    public <T> void preProcess(NativeWebRequest request, DeferredResult<T> deferredResult) throws Exception {
        log.info("DeferredResultProcessingInterceptor preProcess,deferredResult:{}", JacksonUtil.toJson(deferredResult));
        DeferredResultProcessingInterceptor.super.preProcess(request, deferredResult);
    }

    /**
     * <br>在通过DeferredResult.setResult(Object)或DeferredResult.setErrorResult(Object)设置DeferredResult后调用，并且也准备好处理并发结果。
     * <br>当使用接受默认超时结果的构造函数创建DeferredResult时，也可以在超时后调用此方法。
     * <br>参数：
     * <br>request – 当前请求
     * <br>deferredResult – 当前请求的 DeferredResult
     * <br>concurrentResult – DeferredResult的结果
     * <br>抛出：
     * <br>Exception ——如果出现错误
     */
    @Override
    public <T> void postProcess(NativeWebRequest request, DeferredResult<T> deferredResult, Object concurrentResult)
            throws Exception {
        log.info("DeferredResultProcessingInterceptor postProcess,deferredResult:{},concurrentResult:{}",
                JacksonUtil.toJson(deferredResult), JacksonUtil.toJson(concurrentResult));
        DeferredResultProcessingInterceptor.super.postProcess(request, deferredResult, concurrentResult);
    }

    /**
     * <br>在设置DeferredResult之前异步请求超时时从容器线程调用。实现可以调用setResult或setErrorResult来恢复处理。
     * <br>参数：
     * <br>request – 当前请求
     * <br>deferredResult – 当前请求的 DeferredResult；如果设置了DeferredResult ，则恢复并发处理并且不调用后续拦截器
     * <br>回报：
     * <br>如果处理应该继续，则为true ，如果不应调用其他拦截器，则为false
     * <br>抛出：
     * <br>Exception ——如果出现错误
     */
    @Override
    public <T> boolean handleTimeout(NativeWebRequest request, DeferredResult<T> deferredResult) throws Exception {
        log.info("DeferredResultProcessingInterceptor handleTimeout,deferredResult:{}", JacksonUtil.toJson(deferredResult));
        return DeferredResultProcessingInterceptor.super.handleTimeout(request, deferredResult);
    }

    /**
     * <br>在设置DeferredResult之前处理异步请求时发生错误时从容器线程调用。实现可以调用setResult或setErrorResult来恢复处理。
     * <br>参数：
     * <br>request – 当前请求
     * <br>deferredResult – 当前请求的 DeferredResult；如果设置了DeferredResult ，则恢复并发处理并且不调用后续拦截器
     * <br>t – 请求处理时发生的错误
     * <br>回报：
     * <br>如果错误处理应该继续，则为true ；如果其他拦截器应该被绕过而不被调用，则为false
     * <br>抛出：
     * <br>Exception ——如果出现错误
     */
    @Override
    public <T> boolean handleError(NativeWebRequest request, DeferredResult<T> deferredResult, Throwable t) throws Exception {
        log.info("DeferredResultProcessingInterceptor handleError,deferredResult:{}", JacksonUtil.toJson(deferredResult));
        log.error("DeferredResultProcessingInterceptor handleError", t);
        return DeferredResultProcessingInterceptor.super.handleError(request, deferredResult, t);
    }

    /**
     * <br>当异步请求因任何原因（包括超时和网络错误）完成时从容器线程调用。此方法可用于检测DeferredResult实例不再可用。
     * <br>参数：
     * <br>request – 当前请求
     * <br>deferredResult – 当前请求的 DeferredResult
     * <br>抛出：
     * <br>Exception ——如果出现错误
     */
    @Override
    public <T> void afterCompletion(NativeWebRequest request, DeferredResult<T> deferredResult) throws Exception {
        log.info("DeferredResultProcessingInterceptor deferredResult:{}", JacksonUtil.toJson(deferredResult));
        log.info(LogConstant.SPRING_LOG, "DeferredResultProcessingInterceptor afterCompletion 结束");
        DeferredResultProcessingInterceptor.super.afterCompletion(request, deferredResult);
    }
}
